Skip to content

Bump GOBL to v0.508.1 and add conversions via the convert register - #63

Merged
samlown merged 6 commits into
mainfrom
convert
Oct 15, 2026
Merged

samlown merged 6 commits into
mainfrom
convert

Conversation

@samlown

@samlown samlown commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Upgrades GOBL to v0.508.1 and adds conversions between GOBL and external formats, built on GOBL's convert register. This supersedes #22: rather than a hand-maintained list of formats, gobl.dev offers exactly the formats the bundled converters register.

Converters

All are blank-imported in bundle/bundle.go. Together they register 23 formats, 21 of which can export:

Module Formats
gobl.ubl v0.90.0 ubl+en16931-v2017, ubl+peppol+bis-v3
gobl.cii v0.73.0 cii+en16931-v2017, cii+peppol+bis-v3
gobl.de.xinvoice v0.0.7 ubl+/cii+de-xrechnung-v3, cii+de-zugferd-v2 (+basic, +extended)
gobl.fr.ctc v0.0.10 ubl+/cii+fr-ctc-cius-v1, ubl+/cii+fr-ctc-extended-v1, cii+fr-ctc-facturx-v1, cii+fr-facturx-v1 (+basic, +extended), cii+fr-choruspro-v1, cdar+fr-ctc-cdv-v1 (+ppf)
gobl.sa.zatca v0.0.6 ubl+sa-zatca-v1

Surfaces

  • internal/ops — Formats, Import, Export, and CheckFormats. Export wraps documents in an envelope and calculates unsigned envelopes first, so drafts export directly. CheckFormats covers every format that exports the document's schema and reports whether that format accepts the document, with the reasons for refusals.

  • CLI — gobl convert:

    gobl convert invoice.json invoice.xml --to ubl+en16931-v2017   # export; --to takes keys in order of preference
    gobl convert -i invoice.xml                                    # import, format detected (--from limits it)
    gobl convert --list -i                                         # registered formats
  • API — GET /v0/formats, POST /v0/formats (check a document), POST /v0/import, and POST /v0/export?format=….

    • Bodies are raw, so XML can be posted directly.
    • /v0/export returns the key of the format used, and /v0/import the key of the format detected, in the GOBL-Format header, which CORS exposes.
    • + in keys can be left unescaped in query strings.
    • Refusals come back as not-supported with rules faults.
    • The OpenAPI spec is updated.
  • Editor — two modes, with each action directly above the editor it reads from:

    • Build: the GOBL editor fills the page, with the example picker, Envelop and Build above it.
    • Convert: the GOBL editor sits beside an editable document in another format.
      • The GOBL bar holds the example picker, the formats that accept the document (re-checked as you edit), and Export →, which writes into the other editor.
      • The other bar holds ← Import, which replaces the GOBL document and labels the pane with the detected format, plus samples made by exporting the examples into their most specific format.
      • ⌘/Ctrl+Enter runs the action of whichever editor has focus.

    The top bar keeps only the title, the mode switch and dark mode. There are 17 bare-minimum region examples in editor/examples/, labelled from the regime and addon registries. The mode, example, sample and format choices persist across reloads.

Accepting documents

GOBL v0.508.1 removed Format.Addons. Each converter's Accepts now decides, and explains a refusal with faults. The register only consults Accepts during an export, so CheckFormats checks a format by exporting a copy of the envelope to it. Checking all 21 export formats takes about 9 ms. If convert ever exposes Accepts directly, CheckFormats becomes a one-line change. This also fixes the earlier ubl+peppol+bis-v3 gap: it now refuses invoices without EN 16931.

Other module updates

Module Version
gobl v0.507.0 → v0.508.1
gobl.ar.arca / gobl.co.dian new, v0.0.3 (addons moved out of core)
gobl.fi.finvoice v0.0.2 → v0.0.6
gobl.it.sdi v0.81.0 → v0.85.0
gobl.mx.cfdi v0.64.0 → v0.68.0
gobl.pl.ksef v0.45.0 → v0.47.0
gobl.pt.saft v0.0.8 → v0.0.9
  • gobl.pt.saft v0.0.9 requires Go 1.26.1. That raises the go directive in go.mod, and the Docker builder moves to golang:1.26-alpine; the old image has GOTOOLCHAIN=local, so its build would fail. CI reads go.mod, so it needs no change.
  • The 0.508.0 changes are handled: data/addons is gone, and the shortened schema descriptions and new tax/filter schema need refreshed snapshots.

Testing

  • go test -race ./... passes. Every example builds and exports into every format that accepts it, and every invoice export format is accepted by at least one example.
  • I drove the editor in headless Chromium through both modes:
    • building
    • format checks for each regional example
    • export and import in both directions
    • samples and pasted documents
    • Ctrl+Enter following focus
    • a refused document
    • dark mode
    • migrating a stored mode from the old layout
  • I built the Docker image and confirmed the container serves all 23 formats.

Export-only formats

The Factur-X and ZUGFeRD EN 16931 profiles (cii+fr-facturx-v1, cii+de-zugferd-v2) are export-only. Their documents declare exactly the plain EN 16931 guideline ID, so they can't be told apart from cii+en16931-v2017, and gobl.cii doesn't detect formats that have no Import schemas. The editor marks them "(export only)". Its import samples use each example's first importable format (for these two, the BASIC profiles), and a test checks that every sample is detected as the format it was exported into.

🤖 Generated with Claude Code

Upgrade GOBL to v0.508.0 and offer conversions between GOBL and external
formats through its new convert package. Only formats registered with the
register are offered, replacing the hand-maintained format list of #22.

Modules:

  gobl             v0.507.0 -> v0.508.0
  gobl.ar.arca     new      v0.0.3   (ar-arca-v4 moved out of core)
  gobl.co.dian     new      v0.0.3   (co-dian-v2 moved out of core)
  gobl.ubl         new      v0.86.0  (registers ubl+ formats)
  gobl.cii         new      v0.69.0  (registers cii+ formats)
  gobl.fi.finvoice v0.0.2  -> v0.0.6
  gobl.it.sdi      v0.81.0 -> v0.83.0
  gobl.mx.cfdi     v0.64.0 -> v0.68.0
  gobl.pl.ksef     v0.45.0 -> v0.47.0

GOBL 0.508.0 changes handled:

- The ARCA and DIAN addons now live in their own modules; blank-import
  both in the bundle so the approved addon test passes.
- data/addons was removed. Addon definitions are already served from the
  registry, so only the TestListDataDir subtest reading it is dropped.
- Shortened schema descriptions and the new tax/filter schema: refresh
  the correction options snapshots and the bulk schema expectations.

Conversions:

- internal/ops: Formats, Import and Export wrap the convert register.
  Export envelops documents and calculates unsigned envelopes first, so
  drafts can be exported directly.
- CLI: `gobl convert` exports with --to (keys in order of preference),
  imports with format detection otherwise (--from limits it), and lists
  the formats with --list.
- API: GET /v0/formats, POST /v0/import and POST /v0/export?format=,
  taking raw bodies. The format used is returned in a GOBL-Format header,
  exposed through CORS. Unescaped "+" in keys is accepted.
- Editor: an Export picker lists the registered export formats and shows
  the result in a read-only XML pane beside the editor, via /v0/export.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@codecov-commenter

codecov-commenter commented Oct 14, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 31.96481% with 464 lines in your changes missing coverage. Please review.
✅ Project coverage is 64.65%. Comparing base (398b5ab) to head (ef00eba).

Files with missing lines Patch % Lines
editor/editor_templ.go 0.00% 399 Missing ⚠️
internal/ops/convert.go 43.33% 27 Missing and 7 partials ⚠️
editor/examples.go 81.33% 8 Missing and 6 partials ⚠️
cmd/gobl/convert.go 88.23% 4 Missing and 4 partials ⚠️
editor/formats.go 77.41% 6 Missing and 1 partial ⚠️
api/convert.go 95.34% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #63      +/-   ##
==========================================
- Coverage   72.56%   64.65%   -7.92%     
==========================================
  Files          48       53       +5     
  Lines        1994     2580     +586     
==========================================
+ Hits         1447     1668     +221     
- Misses        467      813     +346     
- Partials       80       99      +19     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Rework the editor around three modes:

- Build: as before, the GOBL source is replaced with the built document.
- Export: the source is left untouched; /v0/export builds it internally
  and the result is shown in a read-only viewer. The formats offered are
  those registered with the convert package whose export schemas include
  the document's schema and whose addons are all declared by it, after
  expanding addon requirements as GOBL does when building.
- Import: a separate XML input is converted through /v0/import, and the
  resulting envelope is shown in the viewer.

Add bare-minimum example documents for the US, UK, Spain (with and without
VERI*FACTU), Germany (EN 16931 and XRechnung), France and the Netherlands
(EN 16931), Italy (SDI), Portugal (SAF-T) and Mexico (CFDI). Their region
and label are derived from the regime and addon registries, loaded lazily
so externally implemented addons are registered first. In import mode an
example is offered as the output of its first export format.

Tests build every example and export it into every format the editor
would offer it. ubl+peppol+bis-v3 is recorded as a known gap: it also
exports bill/status, so the EN 16931 addon it needs for invoices is only
checked in Accepts and is missing from the register's metadata.

The mode, example and format are remembered in localStorage.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Upgrade to GOBL v0.508.1 and add the converters that register regional
formats with its convert package:

  gobl             v0.508.0 -> v0.508.1
  gobl.ubl         v0.86.0  -> v0.87.0
  gobl.cii         v0.69.0  -> v0.70.0
  gobl.de.xinvoice new      v0.0.6  (XRechnung, ZUGFeRD)
  gobl.fr.ctc      v0.0.8   -> v0.0.9  (CTC, Factur-X, Chorus Pro, CDAR)
  gobl.sa.zatca    v0.0.4   -> v0.0.5  (ZATCA)
  gobl.it.sdi      v0.83.0  -> v0.84.0
  gobl.pt.saft     v0.0.8   -> v0.0.9

gobl.pt.saft v0.0.9 requires Go 1.26.1, so the go directive moves up and
the Docker builder image moves to golang:1.26-alpine (its GOTOOLCHAIN is
local, so the build would otherwise fail).

GOBL v0.508.1 removes Format.Addons, and converters now explain in
Accepts why they refuse a document, as rules faults. Only a converter can
tell whether it accepts a document, and the register only asks while
exporting, so:

- ops.CheckFormats reports, for each format that exports the document's
  schema, whether it accepts it, by exporting a copy of the envelope, and
  the refusal reasons. It takes about 9ms for all 21 export formats.
- POST /v0/formats exposes the checks through the API and OpenAPI spec.
- The editor's export picker lists the formats the server reports as
  accepting the source, rechecking and re-exporting as it is edited,
  replacing the client-side addon matching. The ubl+peppol+bis-v3 gap
  this had goes away.
- Examples carry the formats that accept them, those specific to their
  country first, so loading one selects its most specific format and
  import samples use it.

Add bare-minimum examples for ZUGFeRD, Factur-X, French CTC, Chorus Pro
and ZATCA, so that every invoice export format is accepted by at least
one example, which a test now checks.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@samlown samlown changed the title Bump GOBL to v0.508.0 and add conversions via the convert register Bump GOBL to v0.508.1 and add conversions via the convert register Oct 15, 2026
samlown and others added 3 commits October 15, 2026 09:55
Replace the build, export and import modes with two:

- Build: the GOBL editor fills the page, with the example picker, envelop
  option and Build button directly above it.
- Convert: the GOBL editor sits beside an editable document in another
  format. The GOBL pane's bar holds the example picker, the formats that
  accept the document and Export, which writes it into the other editor.
  The other pane's bar holds Import, which replaces the GOBL document, and
  samples made by exporting the examples into their most specific format.
  ⌘/Ctrl+Enter runs the action of the focused editor.

The top bar keeps only the title, the mode switch and the dark mode
toggle, and the read-only viewer goes, as results are written into the
editors. Formats are still checked as the GOBL document is edited, but
it is no longer re-exported, so a document pasted on the other side is
not overwritten. Stored export and import modes map onto convert.

/v0/import now returns the detected format in the GOBL-Format header,
via ops.Import, so the other pane can be labelled and the format picker
defaults to exporting back into the format a document was imported from.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
  gobl.ubl         v0.87.0 -> v0.90.0
  gobl.cii         v0.70.0 -> v0.73.0
  gobl.fr.ctc      v0.0.9  -> v0.0.10
  gobl.de.xinvoice v0.0.6  -> v0.0.7
  gobl.sa.zatca    v0.0.5  -> v0.0.6

gobl.ubl and gobl.cii now list the schemas each format imports and
exports separately, and formats without imports are never detected. The
Factur-X and ZUGFeRD EN 16931 profiles (cii+fr-facturx-v1,
cii+de-zugferd-v2) are export-only, as their documents declare the plain
EN 16931 guideline and cannot be told apart from cii+en16931-v2017.

In the editor:

- Samples use the first of an example's formats that can be imported
  back, so a Factur-X or ZUGFeRD example is offered as its BASIC profile
  and imports faithfully. A test checks every sample is detected as the
  format it was exported into.
- Export-only formats are labelled as such in the format picker and the
  other pane's title, as importing their output gives another format.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@samlown
samlown merged commit c64aaa3 into main Oct 15, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants